package com.xdu.yunwufog.connection.netty;

import com.xdu.yunwufog.common.exception.ServerErrorException;
import com.xdu.yunwufog.connection.utils.DataBusConstant;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.DigestUtils;


import java.io.*;
import java.net.InetSocketAddress;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.Callable;

/**
 * 多线程获取连接池中的连接
 * Callable在任务完成之后会有返回值
 * Callable<String>:一个具有类型参数的泛型
 * 1、从连接池中获取一个连接
 *
 */
// 在此处添加测试案例，100MB的图片，和2MB的JSON图片
public class ChannelTaskThread implements Callable<String> {
    // 获取netty连接池，NettyClientPool为单例模式，可以获取全局唯一的连接池
    private final Logger logger = LoggerFactory.getLogger(getClass());
    final NettyClientPool nettyClientPool = NettyClientPool.getInstance();
    private String message;
    private InetSocketAddress socketAddress;

    public  ChannelTaskThread(String message, InetSocketAddress socketAddress) {
        this.message = message;
        this.socketAddress = socketAddress;
    }

    @Override
    public String call() throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        // 同一个线程使用同一个全局唯一的随机数
        long random = Long.parseLong(sdf.format(new Date())) * 1000000 + Math.round(Math.random()*1000000);
        String serverMsg = "";
        try {
            Channel channel = nettyClientPool.getChannel(random,socketAddress,3);
            logger.info("[INFO] Acquire Channel id in channel pool is {}",channel.id());


            // UnpooledByteBufAllocator: 非池化的内存分配器，用于从堆上或直接内存上进行内存的分配和释放；false：在堆上开启buffer
            UnpooledByteBufAllocator allocator = new UnpooledByteBufAllocator(false);
            ByteBuf buf = allocator.buffer();
            // 先写长度，之后再读取长度
            byte[] bytes = message.getBytes(StandardCharsets.UTF_8);

            buf.writeBytes(bytes);

            System.out.println("Send message length is "+bytes.length);

            // 根据特定的handler类型返回对应的handler
            NettyClientHandler tcpHandler = channel.pipeline().get(NettyClientHandler.class);
            ChannelId id = channel.id();

            logger.info("[INFO] SEND SEQNO[{}] MESSAGE AND CHANNEL id [{}]",random,id);
            // 这里的serverMsg就是返回的结果
            serverMsg = tcpHandler.sendMessage(buf,channel);
            // 释放连接
            NettyClientPool.release(channel,socketAddress);
            logger.info("[INFO] Channel {} Receive message length :{}",channel.id(),serverMsg.length());
        } catch (ServerErrorException e){
            return "{'code':500}";
        } catch (Exception e){
            e.printStackTrace();
        }
        return serverMsg.equals("") ? "{'code':500}" : serverMsg;
    }


    @Deprecated
    public static byte[] toByteArray(String filename) throws IOException {

        FileChannel fc = null;
        try {
            fc = new RandomAccessFile(filename, "r").getChannel();
            MappedByteBuffer byteBuffer = fc.map(FileChannel.MapMode.READ_ONLY, 0,
                    fc.size()).load();
            System.out.println(byteBuffer.isLoaded());
            byte[] result = new byte[(int) fc.size()];
            if (byteBuffer.remaining() > 0) {
                byteBuffer.get(result, 0, byteBuffer.remaining());
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            try {
                fc.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
